package com.gxa.community.admin.service.order.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.gxa.community.admin.mapper.OperateTicketMapper;
import com.gxa.community.admin.mapper.goods.GoodsInfoMapper;
import com.gxa.community.admin.mapper.order.*;
import com.gxa.community.admin.service.order.OrderService;
import com.gxa.community.core.pojo.bo.order.OrderAndGoodsInfo;
import com.gxa.community.core.pojo.domain.*;
import com.gxa.community.core.pojo.domain.goodsdo.GoodsInfo;
import com.gxa.community.core.pojo.vo.order.GoodsInfoVo;
import com.gxa.community.core.pojo.vo.order.OrderGoodsVo;
import com.gxa.community.core.pojo.vo.order.OrderInfoVo;
import com.gxa.community.core.pojo.vo.order.UserInfoVo;
import com.gxa.community.core.utils.LittleUtils;
import com.gxa.community.core.utils.R;
import org.apache.activemq.command.ActiveMQObjectMessage;
import org.springframework.jms.annotation.JmsListener;
import org.springframework.stereotype.Service;

import javax.jms.JMSException;
import javax.jms.Message;
import java.math.BigDecimal;
import java.util.*;

import static java.util.stream.Collectors.toSet;

@Service
public class OrderServiceImpl implements OrderService {
    final OrderInfoMapper orderInfoMapper;
    final OrderGoodsInfoMapper orderGoodsInfoMapper;
    final OrderGoodsRelMapper orderGoodsRelMapper;
    final GoodsInfoMapper goodsInfoMapper;
    final UserInfoMapper userInfoMapper;
    final OperateTicketMapper operateTicketMapper;
    final WayBillMapper wayBillMapper;

    public OrderServiceImpl(OrderInfoMapper orderInfoMapper
            , OrderGoodsInfoMapper orderGoodsInfoMapper
            , OrderGoodsRelMapper orderGoodsRelMapper
            , GoodsInfoMapper goodsInfoMapper, UserInfoMapper userInfoMapper, OperateTicketMapper operateTicketMapper, WayBillMapper wayBillMapper) {
        this.orderInfoMapper = orderInfoMapper;
        this.orderGoodsInfoMapper = orderGoodsInfoMapper;
        this.orderGoodsRelMapper = orderGoodsRelMapper;
        this.goodsInfoMapper = goodsInfoMapper;
        this.userInfoMapper = userInfoMapper;
        this.operateTicketMapper = operateTicketMapper;
        this.wayBillMapper = wayBillMapper;
    }

    /**
     * 生成订单
     */
    @Override
    public R createOrder(OrderAndGoodsInfo info) {
        OrderInfoVo orderInfoVo = info.getOrderInfo();
        List<GoodsInfoVo> goodsList = info.getGoodsInfo();

        BigDecimal price = null, payment = null;

        // 生成订单信息
        Long timestamp = System.currentTimeMillis();
        OrderInfo orderInfo = new OrderInfo()
                .setNos(LittleUtils.generateNo(16, timestamp))
                .setCreateTime(timestamp)
                .setAgentId(orderInfoVo.getAgentId())
                .setBuyerId(orderInfoVo.getBuyerId())
                .setReceiverName(orderInfoVo.getReceiverName())
                .setReceiverPhone(orderInfoVo.getReceiverPhone())
                .setCouponId(orderInfoVo.getCouponId())
                .setStatus(1)//待付款
                .setType(orderInfoVo.getType());

        // 遍历商品列表, 封装OrderGoodsRel, 添加订单商品信息
        for (GoodsInfoVo goods : goodsList) {
            // 在商品列表中查询商品
            GoodsInfo goodsDo = goodsInfoMapper.selectOne(new QueryWrapper<GoodsInfo>().eq("no", goods.getNos()).eq("status", 1));
            if (goodsDo == null) return R.error("订单中包含不存在的商品");
            if (goodsDo.getNum() <= goods.getGoodsNum()) return R.error("商品库存不足");

            OrderGoodsInfo orderGoodsInfo = orderGoodsInfoMapper.selectOne(new QueryWrapper<OrderGoodsInfo>()
                    .eq("no", goodsDo.getNos())
                    .eq("name", goodsDo.getName())
                    .eq("original_price", goodsDo.getOriginalPrice())
                    .eq("actual_price", goodsDo.getActualPrice())
                    .eq("commission", goodsDo.getCommission())
            );

            OrderGoodsRel goodsRel = new OrderGoodsRel();

            if (orderGoodsInfo == null) { // 如果订单商品表中没有
                // 将商品信息写入订单商品表
                int insert = orderGoodsInfoMapper.insert(new OrderGoodsInfo()
                        .setName(goodsDo.getName())
                        .setCommission(goodsDo.getCommission())
                        .setActualPrice(goodsDo.getActualPrice())
                        .setNo(goodsDo.getNos())
                        .setPic(goodsDo.getPic())
                        .setOriginalPrice(goodsDo.getOriginalPrice())
                );
                if (insert > 0)
                    goodsRel.setOrderGoodsId(insert);
                else return R.error("订单创建失败");
            } else {
                goodsRel.setOrderGoodsId(orderGoodsInfo.getId());
            }
            goodsRel.setCouponId(goods.getCouponId())
                    .setGoodsNum(goodsRel.getGoodsNum())
                    .setOrderNo(orderInfo.getNos());

            // 将 订单信息与订单商品建立 联系
            orderGoodsRelMapper.insert(goodsRel);

            // 计算打折前销售价格
            price = price.add(goodsDo.getActualPrice().multiply(new BigDecimal(goods.getGoodsNum().toString())));

        }
        // TODO 通过优惠券计算优惠后价格
        //先获取用户使用的消费券面值
        BigDecimal couponPrice = operateTicketMapper.selectCouponPrice(orderInfo.getCouponId());
        payment = price.subtract(couponPrice);
        orderInfo.setPrice(price);
        orderInfo.setPayment(payment);
        // 生成订单信息
        if (orderInfoMapper.insert(orderInfo) > 0)
            // TODO 返回订单信息，前端跳转支付链接
            return R.ok("订单创建成功！").put("data", orderInfo);
        else return R.error("订单创建失败");
    }


    /**
     * 条件查询订单
     */
    @Override
    public R queryOrder(Integer page, Integer size, OrderInfoVo orderInfoVo) {

        // 特殊处理来自团长查询的信息
        // status 11 已付款未发货
        // status 12 已付款已发货
        int status = 0;
        if (orderInfoVo.getStatus() != null && orderInfoVo.getStatus() > 10) {
            status = orderInfoVo.getStatus();
            orderInfoVo.setStatus(2);
        }

        Page<OrderInfo> infoPage = new Page<>(page, size);
        List<Object> buyerIds = null;
        if (StringUtils.isNotBlank(orderInfoVo.getNick()))
            buyerIds = userInfoMapper.selectObjs(new QueryWrapper<UserInfo>().select("user_id")
                    .like("nick_name", orderInfoVo.getNick()));

        // 条件查询订单列表
        Page<OrderInfo> orderInfoPage = new LambdaQueryChainWrapper<>(orderInfoMapper)
                .eq(orderInfoVo.getBuyerId() != null, OrderInfo::getBuyerId, orderInfoVo.getBuyerId()) // 直接根据用户ID查询
                .eq(orderInfoVo.getType() != null, OrderInfo::getType, orderInfoVo.getType())
                .eq(orderInfoVo.getAgentId() != null, OrderInfo::getAgentId, orderInfoVo.getAgentId())
                .eq(StringUtils.isNotBlank(orderInfoVo.getOrderNo()), OrderInfo::getNos, orderInfoVo.getOrderNo())
                .gt(orderInfoVo.getStartTime() != null, OrderInfo::getCreateTime, orderInfoVo.getStartTime())
                .lt(orderInfoVo.getEndTime() != null, OrderInfo::getCreateTime, orderInfoVo.getEndTime())
                .eq(orderInfoVo.getStatus() != null, OrderInfo::getStatus, orderInfoVo.getStatus())
                .in(buyerIds != null, OrderInfo::getBuyerId, buyerIds)
                .eq(StringUtils.isNotBlank(orderInfoVo.getReceiverName()), OrderInfo::getReceiverName, orderInfoVo.getReceiverName())
                .eq(StringUtils.isNotBlank(orderInfoVo.getReceiverPhone()), OrderInfo::getReceiverPhone, orderInfoVo.getReceiverPhone())
                .likeRight(StringUtils.isNotBlank(orderInfoVo.getReceiverPhone()), OrderInfo::getReceiverPhone, orderInfoVo.getReceiverPhone())
                .page(infoPage);

        List<OrderInfo> orders = orderInfoPage.getRecords();

        // 特殊处理来自团长查询的信息
        // 判断订单是否发货 -> 订单对应的运单是否配送中 -> status = 2
        if (status > 10) {
            Set<String> wayBills = new HashSet<>();
            for (OrderInfo order : orders)
                wayBills.add(order.getWaybillNo());

            if (wayBills.isEmpty())
                return R.page(orderInfoPage.getCurrent(), orderInfoPage.getSize(), 0L, new ArrayList<>());

            HashMap<String, Integer> wayStatus = wayBillMapper.selectList(
                    Wrappers.lambdaQuery(WaybillInfo.class)
                            .select(WaybillInfo::getStatus)
                            .in(WaybillInfo::getNo, wayBills)
            ).stream().collect(HashMap::new, (map, way) -> map.put(way.getNo(), way.getStatus()), HashMap::putAll);

            int finalStatus = status - 10;
            orders.removeIf(orderInfo -> wayStatus.get(orderInfo.getWaybillNo()) != finalStatus);
        }

        if (orders == null || orders.isEmpty())
            return R.page(orderInfoPage.getCurrent(), orderInfoPage.getSize(), orderInfoPage.getTotal(), new ArrayList<>());

        // 查询订单关联的团长信息
        HashMap<Integer, UserInfoVo> agentInfos =
                userInfoMapper.selectList(Wrappers.lambdaQuery(UserInfo.class)
                                .in(UserInfo::getUserId, orders.stream().map(OrderInfo::getAgentId).collect(toSet())))
                        .stream().collect(HashMap::new, (map, user) -> map.put(user.getUserId(), userToVo(user)), HashMap::putAll);

        // 查询订单关联的下单信息
        HashMap<Integer, UserInfoVo> buyerInfos =
                userInfoMapper.selectList(Wrappers.lambdaQuery(UserInfo.class)
                                .in(UserInfo::getUserId, orders.stream().map(OrderInfo::getBuyerId).collect(toSet())))
                        .stream().collect(HashMap::new, (map, user) -> map.put(user.getUserId(), userToVo(user)), HashMap::putAll);

        List<OrderInfoVo> infoVos = new ArrayList<>();
        for (OrderInfo order : orders) {
            infoVos.add(
                    new OrderInfoVo()
                            .setAgentInfo(agentInfos.get(order.getAgentId()))
                            .setUserInfo(buyerInfos.get(order.getBuyerId()))
                            .setNo(order.getNos())
                            .setCreateTime(order.getCreateTime())
                            .setReceiverName(order.getReceiverName())
                            .setReceiverPhone(order.getReceiverPhone())
                            .setCouponId(order.getCouponId())
                            .setPrice(order.getPrice().doubleValue())
                            .setPayment(order.getPayment().doubleValue())
                            .setType(order.getType())
                            .setWaybillNo(order.getWaybillNo())
                            .setStatus(order.getStatus())
            );
        }

        return R.page(orderInfoPage.getCurrent(), orderInfoPage.getSize(), orderInfoPage.getTotal(), infoVos);
    }

    /**
     * 根据订单号查询订单下商品信息
     *
     * @param orderNo 订单号
     */
    @Override
    public R queryGoods(List<String> orderNo) {

        // 查询所有订单关联的物品
        HashMap<String, List<OrderGoodsRel>> goodsRelList = orderGoodsRelMapper.selectList(
                Wrappers.lambdaQuery(OrderGoodsRel.class)
                        .in(OrderGoodsRel::getOrderNo, orderNo)
        ).stream().collect(HashMap::new, (map, o) -> {
            if (map.containsKey(o.getOrderNo()))
                map.get(o.getOrderNo()).add(o);
            else {
                List<OrderGoodsRel> list = new ArrayList<>();
                list.add(o);
                map.put(o.getOrderNo(), list);
            }
        }, HashMap::putAll);

        if (goodsRelList.isEmpty()) return R.ok();

        // 拿到所有待查询的商品id
        Set<Integer> goodsIds = new HashSet<>();
        for (List<OrderGoodsRel> value : goodsRelList.values()) {
            goodsIds.addAll(
                    value.stream().map(OrderGoodsRel::getOrderGoodsId).collect(toSet())
            );
        }

        if (goodsIds.isEmpty()) return R.ok();

        // 根据商品id查询商品信息
        HashMap<Integer, OrderGoodsInfo> goodsInfos = orderGoodsInfoMapper.selectList(
                Wrappers.lambdaQuery(OrderGoodsInfo.class)
                        .in(OrderGoodsInfo::getId, goodsIds)
        ).stream().collect(HashMap::new, (map, o) -> map.put(o.getId(), o), HashMap::putAll);

        if (goodsInfos.isEmpty()) return R.ok();

        HashMap<String, List<OrderGoodsVo>> data = new HashMap<>();
        for (String s : goodsRelList.keySet()) {
            for (OrderGoodsRel goodsRel : goodsRelList.get(s)) {
                OrderGoodsVo goodsVo = new OrderGoodsVo()
                        .setId(goodsRel.getOrderGoodsId())
                        .setNo(goodsInfos.get(goodsRel.getOrderGoodsId()).getNo())
                        .setName(goodsInfos.get(goodsRel.getOrderGoodsId()).getName())
                        .setOriginalPrice(goodsInfos.get(goodsRel.getOrderGoodsId()).getOriginalPrice())
                        .setActualPrice(goodsInfos.get(goodsRel.getOrderGoodsId()).getActualPrice())
                        .setCommission(goodsInfos.get(goodsRel.getOrderGoodsId()).getCommission())
                        .setPic(goodsInfos.get(goodsRel.getOrderGoodsId()).getPic())
                        .setNum(goodsRel.getGoodsNum())
                        .setStatus(goodsInfos.get(goodsRel.getOrderGoodsId()).getStatus());

                if (data.containsKey(s)) {
                    data.get(s).add(goodsVo);
                } else {
                    List<OrderGoodsVo> list = new ArrayList<>();
                    list.add(goodsVo);
                    data.put(s, list);
                }
            }
        }
        return R.ok().put("data", data);
    }

    /**
     * 用户支付成功, 修改订单状态
     * 从 orderPaySuccess 的通道上监听
     *
     * @param message 订单编号
     */
    @JmsListener(destination = "orderPaySuccess")
    public void receive1(Message message) throws JMSException {

        ActiveMQObjectMessage objectMessage = (ActiveMQObjectMessage) message;
        String orderNo = (String) objectMessage.getObject();

        // 根据订单编号修改订单状态为已支付
        if (StringUtils.isNotBlank(orderNo))
            orderInfoMapper.update(
                    new OrderInfo().setStatus(2),
                    Wrappers.lambdaUpdate(OrderInfo.class)
                            .eq(OrderInfo::getStatus, 1)
                            .eq(OrderInfo::getNos, orderNo)
            );

        message.acknowledge();
    }

    private UserInfoVo userToVo(UserInfo userInfo) {
        UserInfoVo userInfoVo = new UserInfoVo();
        /*
        userId
        nickName
        address
        createTime
        phone
         */
        return userInfoVo.setUserId(userInfo.getUserId())
                .setNickName(userInfo.getNickName())
                .setAddress(userInfo.getAddress())
                .setCreateTime(userInfo.getCreateTime())
                .setPhone(userInfo.getPhone());
    }
}
